package com.inspur.security.cbb3.kms.keymanager.containers.service.impl;

import com.inspur.security.cbb3.kms.enums.ContainerType;
import com.inspur.security.cbb3.kms.exception.UserInfoInVaildException;
import com.inspur.security.cbb3.kms.keymanager.containers.po.ContainersBean;
import com.inspur.security.cbb3.kms.keymanager.containers.repository.ContainersRepository;
import com.inspur.security.cbb3.kms.keymanager.containers.service.ContainersService;
import com.inspur.security.cbb3.kms.keymanager.containers.vo.SecretRefVO;
import com.inspur.security.cbb3.kms.keymanager.containersecret.po.ContainerSecretBean;
import com.inspur.security.cbb3.kms.keymanager.containersecret.repository.ContainerSecretRepository;
import com.inspur.security.cbb3.kms.keymanager.secrets.po.SecretsBean;
import com.inspur.security.cbb3.kms.keymanager.secrets.repository.SecretsRepository;
import com.inspur.security.cbb3.kms.keymanager.secrets.service.SecretsService;
import com.inspur.security.cbb3.kms.sysuser.po.SysUserBean;
import com.inspur.security.cbb3.kms.sysuser.service.SysUserService;
import com.inspur.security.cbb3.kms.utils.DateUtil;
import com.inspur.security.cbb3.kms.utils.PageRequestDate;
import javassist.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.MissingServletRequestParameterException;

import javax.persistence.criteria.Predicate;
import javax.validation.ValidationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: lijunchang
 * @Description: 密钥容器service实现
 * @Date: 2020/10/19
 */
@Service
@Slf4j
@Transactional(readOnly = true)
public class ContainersServiceImpl implements ContainersService {


    @Autowired
    private ContainersRepository containersRepository;
    @Autowired
    private ContainerSecretRepository containerSecretRepository;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SecretsService secretsService;

    /**
     * 进行密钥容器分页查询
     *
     * @param pageRequestDate 分页参数
     * @param searchParams    查询条件
     * @return 查询结果集
     */
    @Override
    public Page searchContainers(PageRequestDate pageRequestDate, ContainersBean searchParams) {
        SysUserBean loginUser = sysUserService.findLoginSysUser();
        if (loginUser == null) {
            throw new UserInfoInVaildException();
        }
        //进行分页设置
        return containersRepository.findAll((Specification<ContainersBean>) (root, query, cb) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(cb.equal(root.get("creatorId").as(String.class), loginUser.getUuid()));
            list.add(cb.equal(root.get("deleted").as(Boolean.class), false));
            //TODO 查询条件
            if (StringUtils.isNotBlank(searchParams.getName())) {
                list.add(cb.like(root.get("name").as(String.class), "%" + searchParams.getName().trim() + "%"));
            }
            if (StringUtils.isNotEmpty(searchParams.getCreatedTimeBegin())) {
                list.add(cb.greaterThanOrEqualTo(root.get("createdTime").as(String.class), searchParams.getCreatedTimeBegin().trim()));
            }
            if (StringUtils.isNotEmpty(searchParams.getCreatedTimeEnd())) {
                list.add(cb.lessThanOrEqualTo(root.get("createdTime").as(String.class), searchParams.getCreatedTimeEnd().trim()));
            }
            Predicate[] p = new Predicate[list.size()];
            return cb.and(list.toArray(p));
        }, pageRequestDate.getPageRequest());

    }

    /**
     * 进行密钥容器单个查询
     *
     * @param uuid 密钥主键
     * @return 查询结果
     */
    @Override
    public ContainersBean searchContainers(String uuid) throws NotFoundException, MissingServletRequestParameterException {
        return checkPermission(uuid);
    }

    /**
     * 密钥容器删除
     *
     * @param uuid 密钥主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteContainer(String uuid) throws NotFoundException, MissingServletRequestParameterException {
        ContainersBean bean = checkPermission(uuid);
        bean.setDeleted(true);
        containersRepository.saveAndFlush(bean);
        List<ContainerSecretBean> rels = containerSecretRepository.findByContainerId(uuid);
        if (CollectionUtils.isEmpty(rels)) {
            return;
        }
        containerSecretRepository.deleteInBatch(rels);
    }

    /**
     * 进行容器新增
     *
     * @param name      容器名称
     * @param creatorId 创建人
     * @return 新增容器对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContainersBean saveContainersBean(String name, String creatorId) {
        ContainersBean containersBean = new ContainersBean();
        containersBean.setName(name);
        containersBean.setType(ContainerType.Asymmetric.name());
        containersBean.setDeleted(false);
        containersBean.setCreatorId(creatorId);
        containersBean.setCreatedTime(DateUtil.getNowDate());
        return containersRepository.save(containersBean);
    }

    /**
     * 进行前端直接传入容器新增
     *
     * @param containersBean 容器对象
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContainersBean addContainers(ContainersBean containersBean) throws NotFoundException, MissingServletRequestParameterException {
        SysUserBean loginUser = sysUserService.findLoginSysUser();
        if (loginUser == null) {
            throw new UserInfoInVaildException();
        }
        //参数校验
        if (ContainerType.getByType(containersBean.getType()).equals(ContainerType.OTHER)) {
            throw new ValidationException("传入容器类型不合规");
        }
        long count = containersRepository.countByNameAndDeletedAndCreatorId(containersBean.getName().trim(),false, loginUser.getUuid());
        if (count > 0) {
            throw new ValidationException("传入容器名称已存在");
        }
        //进行容器保存
        containersBean.setDeleted(false);
        containersBean.setCreatorId(loginUser.getUuid());
        containersBean.setCreatedTime(DateUtil.getNowDate());
        containersRepository.saveAndFlush(containersBean);

        List<SecretRefVO> secretRefS = containersBean.getSecretRefS();
        if (CollectionUtils.isEmpty(secretRefS)) {
            return containersBean;
        }
        List<String> addedSecretUuids = new ArrayList<>();
        for (SecretRefVO sr : secretRefS) {
            String secretUuid = StringUtils.isBlank(sr.getSecretUuid()) ? sr.getSecretRef() : sr.getSecretUuid();
            if (StringUtils.isBlank(secretUuid)) {
                continue;
            }
            if (addedSecretUuids.contains(secretUuid)) {
                continue;
            }
            SecretsBean sb = secretsService.searchSecret(secretUuid);
            ContainerSecretBean csb = new ContainerSecretBean();
            csb.setName(sb.getName());
            csb.setNote(sb.getNote());
            csb.setSecretId(secretUuid);
            csb.setContainerId(containersBean.getUuid());
            csb.setDeleted(false);
            csb.setCreatedTime(containersBean.getCreatedTime());
            containerSecretRepository.save(csb);
        }
        return containersBean;
    }

    /**
     * 向容器中添加密钥
     *
     * @param uuid       容器uuid
     * @param secretUuid 密钥uuid
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSecretsToContainer(String uuid, String secretUuid) throws NotFoundException, MissingServletRequestParameterException {
        SysUserBean loginUser = sysUserService.findLoginSysUser();
        if (loginUser == null) {
            throw new UserInfoInVaildException();
        }
        //是否有权限新增
        ContainersBean bean = checkPermission(uuid);
        //校验是否已经添加过
        List<ContainerSecretBean> rels = containerSecretRepository.findByContainerIdAndSecretIdOrderByCreatedTimeDesc(uuid, secretUuid);
        if (!CollectionUtils.isEmpty(rels)) {
            throw new ValidationException("该容器中已包含该密钥");
        }
        SecretsBean sb = secretsService.searchSecret(secretUuid);
        ContainerSecretBean csb = new ContainerSecretBean();
        csb.setName(sb.getName());
        csb.setNote(sb.getNote());
        csb.setSecretId(secretUuid);
        csb.setContainerId(uuid);
        csb.setDeleted(false);
        csb.setCreatedTime(DateUtil.getNowDate());
        containerSecretRepository.save(csb);
    }

    /**
     * 删除容器中的密钥
     *
     * @param uuid       容器uuid
     * @param secretUuid 密钥uuid
     */
    @Override
    public void deleteSecretsFromContainer(String uuid, String secretUuid) throws NotFoundException, MissingServletRequestParameterException {
        SysUserBean loginUser = sysUserService.findLoginSysUser();
        if (loginUser == null) {
            throw new UserInfoInVaildException();
        }
        //是否有权限新增
        ContainersBean bean = checkPermission(uuid);
        //校验是否已经添加过
        List<ContainerSecretBean> rels = containerSecretRepository.findByContainerIdAndSecretIdOrderByCreatedTimeDesc(uuid, secretUuid);
        if (CollectionUtils.isEmpty(rels)) {
            throw new ValidationException("该容器中不包含该密钥");
        }
        containerSecretRepository.deleteInBatch(rels);
    }

    /**
     * 校验登录用户是否有数据的操作权限
     *
     * @param uuid 数据id
     * @return 数据对象
     * @throws MissingServletRequestParameterException 异常信息-主键参数必填
     * @throws NotFoundException                       异常信息-未找到对象
     */
    private ContainersBean checkPermission(String uuid) throws MissingServletRequestParameterException, NotFoundException {
        if (StringUtils.isBlank(uuid)) {
            throw new MissingServletRequestParameterException("主键字段uuid", "String");
        }
        SysUserBean loginUser = sysUserService.findLoginSysUser();
        if (loginUser == null) {
            throw new UserInfoInVaildException();
        }
        Optional<ContainersBean> optional = containersRepository.findById(uuid);
        //校验是否存在，如果不存在，直接返回成功
        if (!optional.isPresent()) {
            throw new NotFoundException("密钥容器对象不存在");
        }
        ContainersBean bean = optional.get();
        //被删除
        if (bean.getDeleted() || !loginUser.getUuid().equalsIgnoreCase(bean.getCreatorId())) {
            throw new NotFoundException("密钥容器对象不存在");
        }
        return bean;
    }
}
